﻿using Engine;
using Engine.Graphics;
using Engine.Media;
using Game;
using System.Collections.Generic;

namespace Command
{
    public class ClayBlock : Game.ClayBlock, IPaintableBlock
    {
        public new const int Index = 72;

        public static string CommandCategory = "命令方块彩色黏土";

        public override int GetFaceTextureSlot(int face, int value)
        {
            Color clayColor = GetCommandColor(Terrain.ExtractData(value));
            if (!IsColored(Terrain.ExtractData(value)) && IsDefaultColor(clayColor))
            {
                return DefaultTextureSlot;
            }
            return 15;
        }

        public override IEnumerable<int> GetCreativeValues()
        {
            if (SubsystemCommandDef.DisplayColorBlock)
            {
                List<int> creativeValues = new List<int>();
                for (int i = 0; i < 4096; i++)
                {
                    creativeValues.Add(Index + i * 32 * 16384);
                }
                return creativeValues;
            }
            else
            {
                return base.GetCreativeValues();
            }
        }

        public override string GetCategory(int value)
        {
            int data = Terrain.ExtractData(value);
            if (SubsystemCommandDef.DisplayColorBlock && !IsDefaultColor(GetCommandColor(data)))
            {
                return CommandCategory;
            }
            return base.GetCategory(value);
        }

        public override void GenerateTerrainVertices(BlockGeometryGenerator generator, TerrainGeometry geometry, int value, int x, int y, int z)
        {
            int data = Terrain.ExtractData(value);
            Color clayColor = GetCommandColor(data);
            if (IsDefaultColor(clayColor))
            {
                clayColor = SubsystemPalette.GetColor(generator, GetColor(data));
            }
            Color color = clayColor;
            generator.GenerateCubeVertices(this, value, x, y, z, color, geometry.OpaqueSubsetsByFace);
        }

        public override void DrawBlock(PrimitivesRenderer3D primitivesRenderer, int value, Color color, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData)
        {
            int data = Terrain.ExtractData(value);
            Color clayColor = GetCommandColor(data);
            if (IsDefaultColor(clayColor))
            {
                clayColor = SubsystemPalette.GetColor(environmentData, GetColor(data));
            }
            color *= clayColor;
            BlocksManager.DrawCubeBlock(primitivesRenderer, value, new Vector3(size), ref matrix, color, color, environmentData);
        }

        public override BlockDebrisParticleSystem CreateDebrisParticleSystem(SubsystemTerrain subsystemTerrain, Vector3 position, int value, float strength)
        {
            int data = Terrain.ExtractData(value);
            Color clayColor = GetCommandColor(data);
            if (IsDefaultColor(clayColor))
            {
                clayColor = SubsystemPalette.GetColor(subsystemTerrain, GetColor(data));
            }
            Color color = clayColor;
            return new BlockDebrisParticleSystem(subsystemTerrain, position, strength, DestructionDebrisScale, color, GetFaceTextureSlot(0, value));
        }

        public override void GetDropValues(SubsystemTerrain subsystemTerrain, int oldValue, int newValue, int toolLevel, List<BlockDropValue> dropValues, out bool showDebris)
        {
            int data = Terrain.ExtractData(oldValue);
            Color clayColor = GetCommandColor(data);
            if (GetColor(data).HasValue || !IsDefaultColor(clayColor))
            {
                showDebris = true;
                if (toolLevel >= RequiredToolLevel)
                {
                    dropValues.Add(new BlockDropValue
                    {
                        Value = Terrain.MakeBlockValue(DefaultDropContent, 0, data),
                        Count = (int)DefaultDropCount
                    });
                }
            }
            else
            {
                base.GetDropValues(subsystemTerrain, oldValue, newValue, toolLevel, dropValues, out showDebris);
            }
        }

        public static Color GetCommandColor(int data)
        {
            int colorData = (data >> 5) & 0xFFF;
            int R = (colorData >> 8) & 0xF;
            int G = (colorData >> 4) & 0xF;
            int B = (colorData & 0xF);
            return new Color(R * 16, G * 16, B * 16) + new Color(15, 15, 15);
        }

        public static int SetCommandColor(int value, Color color)
        {
            color -= new Color(15, 15, 15);
            int R = (int)(color.R / 16f) << 8;
            int G = (int)(color.G / 16f) << 4;
            int B = (int)(color.B / 16f);
            int colorData = ((R | G | B) & 0xFFF) << 5;
            return Terrain.ReplaceData(value, colorData);
        }

        public static bool IsDefaultColor(Color color)
        {
            return color.R == 15 && color.G == 15 && color.B == 15;
        }

        public new int Paint(SubsystemTerrain terrain, int value, int? color)
        {
            value = SetCommandColor(value, new Color(15, 15, 15));
            int data = Terrain.ExtractData(value);
            return Terrain.ReplaceData(value, SetColor(data, color));
        }
    }
}